/* 
 * A664p7_ip.c -- Implements IP utility functions
 *
 *
 *------------------------------------------------------------------------------
 *
 *                    ---   PROPRIETARY NOTICE   ---
 *
 *   The information contained herein is proprietary to Smiths Aerospace.
 *   and shall not be reproduced or disclosed in whole or in part or used
 *   for any design or manufacture except when such user possesses direct
 *   written authorization from Smiths Aerospace.
 *
 *   Copyright 2006, Smiths Aerospace.
 *
 *------------------------------------------------------------------------------
 *
 * modification history
 * --------------------
 * 30 mar 06	Huizenga	Initial revision.
 * 09 may 06	Huizenga	Added additional comments
 * 09 may 06	Huizenga	Modified functions returning "void" to return an int indicating fail/success
 */

#include "pcap.h"

#ifndef WIN32
	#include <sys/socket.h>
	#include <netinet/in.h>
#else
	#include <winsock.h>
#endif
#include "A664p7_internal.h"



/* 
 * generate_ip_checksum: Generates a checksum for a given IP header, but does not update the checksum field
 *		INPUTS: hdr -- A pointer to the IP_HEADER structure to checksum
 *		RETURNS: Correct IP checksum for the given IP header
 */
unsigned short int generate_ip_checksum(IP_HEADER *hdr)
{
	unsigned long sum = 0;
	unsigned short *buf = (unsigned short *)hdr;	/* Treat the header as an array of 16 bit words */
	int nwords = sizeof(IP_HEADER)/2;
	int oldck = hdr->check;
	hdr->check = 0;									/* Need to set checksum field to zero to get a correct checksum */
	for (sum = 0; nwords > 0; nwords--)
		sum += *buf++;								/* Sum up value of all words */

	while(sum > 0xffff)								/* This loop combines the result into two bytes */
		sum = (sum >> 16) + (sum & 0xffff);			/* Add two least significant bytes to the next two bytes */
	hdr->check = oldck;
	return (unsigned short int)~sum;				/* 1's complement & return */
}

/*
 * ih_to_net:  Converts an IP_HEADER structure to network order
 * INPUTS: h -- A pointer to the IP_HEADER structure to be modified
 * RETURNS: A664P7_FAIL if h == NULL, A664P7_SUCC otherwise
 */
int ih_to_net(IP_HEADER *h)
{
	if(!h)
		return A664P7_FAIL;

	h->len = htons(h->len);
	return A664P7_SUCC;
}

/*
 * ih_from_net:  Converts an IP_HEADER structure from network order
 * INPUTS: h -- A pointer to the IP_HEADER structure to be modified 
 * RETURNS: A664P7_FAIL if h == NULL, A664P7_SUCC otherwise
 */
int ih_from_net(IP_HEADER *h)
{
	if(!h)
		return A664P7_FAIL;

	h->len = ntohs(h->len);
	return A664P7_SUCC;
}

/*
 * initialize_ip_header:  Sets the constants & initial values in an IP_HEADER structure,
 *                              converts it to network order
 * INPUTS: h -- A pointer to the IP_HEADER structure to be modified 
 * RETURNS: A664P7_FAIL if h == NULL, A664P7_SUCC otherwise
 */
int initialize_ip_header(IP_HEADER *h)
{
	if(!h)
		return A664P7_FAIL;

	h->ver = 4;						/* Version */
	h->hl = sizeof(IP_HEADER)/4;	/* Header length .. always 5 */
	h->len = sizeof(IP_HEADER);
	ih_to_net(h);
	h->ttl = 1;
	h->protocol = PROT_UDP;
	h->check = generate_ip_checksum(h);

	return A664P7_SUCC;
}

/*
 * initialize_ip_header:  Sets non-constant values in IP header, updates the checksum
 * INPUTS: h -- A pointer to the IP_HEADER structure to be modified 
 *         src -- The source IP address to be copied into the header
 *         dst -- The destination IP address to be copied into the header
 * RETURNS: A664P7_FAIL if h == NULL, A664P7_SUCC otherwise
 */
int populate_ip_header(IP_HEADER *h, unsigned int src_ip, unsigned int dst_ip)
{
	if(!h)
		return A664P7_FAIL;

	h->src = htonl(src_ip);
	h->dst = htonl(dst_ip);
	h->check = generate_ip_checksum(h);

	return A664P7_SUCC;
}

